<?php
//    echo "hello world.\n";
define("MAGIC_NUM", 0x19831201);
define("MAX_FILE_SIZE", 1<<30);
define("HEAD_FORMAT_KV", "Imagic_num/Iblock_id/Itimestamp/Ilog_id/I2check_sum/I2reserved/Iblock_size");

class qreader
{
    private $m_path;
    private $m_file;
    private $m_offset_file;
    private $m_qfp;

    public function __construct($strPath, $strFile, $strChannelOffsetFile, $intCheckInterval)
    {
        $this->m_path    = $strPath;
        $this->m_file    = $strFile;
        $this->m_offset_file = $strChannelOffsetFile;
        $this->m_check_interval = $intCheckInterval;
        $this->m_offset_fp = NULL;
        $this->m_queue_fp  = NULL;

        $this->m_file_no  = 0;
        $this->m_offset   = 0;
        $this->m_block_id = 0;

    }

    public function __destruct()
    {
        @fclose($this->m_offset_fp);
        @fclose($this->m_queue_fp);
    }

    private function detect_file()
    {
        $max_file_no = -1;
        if (is_dir($this->m_path)) {
            if ($dh = opendir($this->m_path)) {
                while (($file = readdir($dh)) !== false) {
                    $arrString = explode(".", $file);
//                    print_r($arrString);
                    if ($arrString[0] == $this->m_file)
                    {
                        $max_file_no = $max_file_no < intval($arrString[1]) ? intval($arrString[1]) : $max_file_no;
                    }
                }
                closedir($dh);
            }
        }
        return $max_file_no;
    }

//    private function readn()
//    {
//    }

    public  function seek_message()
    {
        $this->load_offset();
        $strFile = $this->m_path.$this->m_file.".".$this->m_file_no;
        if (FALSE == ($this->m_queue_fp = fopen($strFile, "r")))
        {
            die("open $strFile FAIL\n");
        }
        if (0 < $this->m_block_id)
        {
            while(1)
            {
                $binHead = fread($this->m_queue_fp, 36);
                assert(36 == strlen($binHead));
                $arrHead = unpack(HEAD_FORMAT_KV, $binHead);
                assert($arrHead['magic_num'] == MAGIC_NUM);
                $stepsize = (($arrHead['block_size'] + 3 ) >> 2 ) << 2;
                assert (0 == fseek($this->m_queue_fp, $stepsize, SEEK_CUR));
                $this->m_offset = ftell($this->m_queue_fp);
                assert ($arrHead['block_id'] < $this->m_block_id);
                if ($this->m_block_id - 1 == $arrHead['block_id'])
                {
                    echo "hit the offset ".$this->m_offset."\n";
                    break;
                }
            }
        }
    }

    public  function read_message()
    {
        $intTryCount = 0;
        $intReadSize = 0;
        $strReadBuff = "";
        var_dump($this->m_offset);

        while(1)
        {
            if ($intTryCount > 2 && ($this->m_file_no < $this->detect_file()))
            {
                $intTryCount = 0;
                fclose($this->m_queue_fp);
                $this->m_file_no += 1;

                $strFile = $this->m_path.$this->m_file.".".$this->m_file_no;
                fclose($this->m_queue_fp);
                if (FALSE == ($this->m_queue_fp = fopen($strFile, "r")))
                {
                    die("open $strFile FAIL\n");
                }
                $this->m_offset = 0;
                $this->m_block_id = 0;
                echo "change to new file[$this->m_file_no].\n";
                continue;
            }
            $strFile = $this->m_path.$this->m_file.".".$this->m_file_no;
            $intFileSize = filesize($strFile);
            if ($intFileSize == $this->m_offset)
            {
                usleep($this->m_check_interval);
                $intTryCount++;
                echo "filesize[$intFileSize] offset[$this->m_offset] no new data, wait.\n";
                continue;
            }
            else
            {
                $arrMessage = array();
                $binHead = fread($this->m_queue_fp, 36);
                assert(36 == strlen($binHead));
                $arrHead = unpack(HEAD_FORMAT_KV, $binHead);
                var_dump($arrHead);
                assert($arrHead['magic_num'] == MAGIC_NUM);
                $stepsize = (($arrHead['block_size'] + 3 ) >> 2 ) << 2;
                $arrMessage['intReadSize'] = $arrHead['block_size'];
                $arrMessage['strReadBuff'] = fread($this->m_queue_fp, $stepsize);
                assert ($stepsize == strlen($arrMessage['strReadBuff']));
                $arrMessage['strReadBuff'] = substr($arrMessage['strReadBuff'], 0, $arrMessage['intReadSize']);
                $this->m_offset = ftell($this->m_queue_fp);
                assert ($arrHead['block_id'] == $this->m_block_id);
                $this->m_block_id ++;
                $arrMessage['intOffset']  = $this->m_offset;
                $arrMessage['intFileNo']  = $this->m_file_no;
                $arrMessage['intBlockID'] = $this->m_block_id;
                echo "read success offset[$this->m_offset] block_id[$this->m_block_id]\n";
                return $arrMessage;
            }
        }
    }

    private  function load_offset()
    {
        $this->m_offset_fp = fopen($this->m_offset_file, "r+");
        if ($this->m_offset_fp == FALSE)
        {
            die("open channel offset file: ".$this->m_offset_file." FAIL\n");
        }
        $file_no_found = false;
        $offset_found = false;
        $block_id_found = false;
        while (1)
        {
            $strLine = fgets($this->m_offset_fp);
            if (0 == strlen($strLine))
            {
                break;
            }
            $arrString = split(":", $strLine);
            if ("file_no" == trim($arrString[0]))
            {
                $this->m_file_no = intval(trim($arrString[1]));
                $file_no_found = true;
            }
            if ("offset" == trim($arrString[0]))
            {
                $this->m_offset = intval(trim($arrString[1]));
                $offset_found = true;
            }
            if ("block_id" == trim($arrString[0]))
            {
                $this->m_block_id = intval(trim($arrString[1]));
                $block_id_found = true;
            }
        }
        if (!$file_no_found || !$offset_found || !$block_id_found)
        {
            die("load file_no[$this->m_file_no] offset[$this->m_offset] block_id[$this->m_block_id] error.\n");
        }
    }

    public  function save_offset()
    {
        ftruncate($this->m_offset_fp, 0);
        rewind($this->m_offset_fp);
        fwrite($this->m_offset_fp, "file_no  : ".$this->m_file_no."\n");
        fwrite($this->m_offset_fp, "offset   : ".$this->m_offset."\n");
        fwrite($this->m_offset_fp, "block_id : ".$this->m_block_id."\n");
        fflush($this->m_offset_fp);
    }
};
?>
